package org.ala.tiktools.mybatis.executor;

import org.ala.tiktools.tools.CachingKVTools;
import org.apache.ibatis.annotations.Param;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ala
 * @date 2025-03-09 14:48
 */
public class ParameterConvert {


    /**
     *  单例
     */
    static ParameterConvert instance;
    public static ParameterConvert instance() {
        if (instance == null) {
            synchronized (ParameterConvert.class) {
                if (instance == null) {
                    instance = new ParameterConvert();
                }
            }
        }
        return instance;
    }


    /**
     *  原mybatis逻辑：
     *  1）如果所有参数都不含@Param注解，取第一个参数作为mybatis执行参数
     *  2）否则按@Param注解组合成Map返回
     */
    public Object convert(Method method, Object[] args, Map<String, Object> appends) {
        Param[] ps = paramIndex.get(method);
        //  如果不存在@Param注解，取第一个参数
        if (ps == null) {
            return args.length > 0 ? args[0] : null;
        }

        //  否则根据@Param注解转换成Map
        HashMap<String, Object> map = new HashMap<>();
        for (int i = 0; i < ps.length; i++) {
            Param param = ps[i];
            map.put(param.value(), args[i]);
        }
        //  追加appends
        if (appends != null) {map.putAll(appends);}
        return map;
    }

    protected Param[] NULL = new Param[]{};
    /**
     *  方法参数的下标和@Param注解映射
     */
    protected CachingKVTools<Method, Param[]> paramIndex = new CachingKVTools<>(NULL, m -> {
        Param[] ps = new Param[m.getParameters().length];
        boolean has = false;
        for (int i = 0; i < m.getParameters().length; i++) {
            Parameter p = m.getParameters()[i];
            Annotation[] annos = p.getAnnotations();
            if (annos == null || annos.length == 0) {continue;}
            for (Annotation anno : annos) {
                if (anno instanceof Param) {
                    ps[i] = (Param) anno;
                    has = true;
                }
            }
        }
        return has ? ps : null;
    });
}
